/*
 * ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
 */

package org.modelcc.language.syntax;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;

import org.modelcc.ModelCCProcess;
import org.modelcc.language.metamodel.LanguageElement;
import org.modelcc.language.metamodel.LanguageModel;

/**
 * Symbol builder.
 * 
 * @author Luis Quesada (lquesada@modelcc.org) & Fernando Berzal (fberzal@modelcc.org)
 */
public abstract class SymbolBuilder extends ModelCCProcess 
{
	private LanguageModel model;

	/**
	 * Default constructor
	 */
	public SymbolBuilder ()
	{
		this.model = null;
	}
	
	/**
	 * Constructor
	 * @param model Language model
	 */
	public SymbolBuilder (LanguageModel model)
	{
		this.model = model;
	}
	
	/**
	 * Get language model
	 * @return The language model
	 */
	public LanguageModel getModel ()
	{
		return model;
	}
	
    /**
     * Build a symbol, fill it, and validate it.
     * @param t symbol to be built.
     * @param data parser metadata.
     * @return true if the symbol is valid, false if not.
     */
    public abstract boolean build (Symbol t, ParserMetadata data);
    
    
    // Ancillary methods
    
	protected final void runSetupMethods (Object o,LanguageElement el) 
		throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException 
	{
		if (getModel().getSuperelements().get(el) != null) {
			runSetupMethods(o,getModel().getSuperelements().get(el));
		}
        if (el.getSetupMethod() != null) {
            Method mtd = el.getElementClass().getDeclaredMethod(el.getSetupMethod(),new Class[]{});
            if (mtd != null) {
                mtd.setAccessible(true);
                try {
                    mtd.invoke(o);
				} catch (Exception e) {
	                log(Level.SEVERE, "Exception when invoking method \"{0}\" of class class \"{1}\".", new Object[]{mtd.getName(),el.getElementClass().getCanonicalName()});
					throw e;
				}
            }
        }
	}

	protected final boolean runConstraints (Object o, LanguageElement el)
		throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException 
	{
		boolean valid = true;
		if (getModel().getSuperelements().get(el) != null) {
			valid &= runConstraints(o,getModel().getSuperelements().get(el));
		}
        for (int i = 0;i < el.getConstraintMethods().size();i++) {
            Method mtd = el.getElementClass().getDeclaredMethod(el.getConstraintMethods().get(i),new Class[]{});
            if (mtd != null) {
                mtd.setAccessible(true);
                try {
                    valid &= (Boolean)mtd.invoke(o);
				} catch (Exception e) {
	                log(Level.SEVERE, "Exception when invoking method \"{0}\" of class class \"{1}\".", new Object[]{mtd.getName(),el.getElementClass().getCanonicalName()});
					throw e;
				}
            }
        }
		return valid;
	}
    
}
